/*
 * @Author: zhangyang
 * @Date: 2021-11-12 10:12:09
 * @LastEditTime: 2021-11-22 16:11:12
 * @Description:  接收直播流
 */
export class WebRtcReciver {

  private pc: RTCPeerConnection | null;
  private defaultPath = '/rtc/v1/play/';
  public stream: MediaStream;

  constructor() {
    /**
     * 免费打洞的信令服务器
     * 按需使用
     */
    // const freeStunServers = [
    //   'stun:stun1.l.google.com:19302',
    //   'stun:stun2.l.google.com:19302',
    //   'stun:stun3.l.google.com:19302',
    //   'stun:stun4.l.google.com:19302',
    //   'stun:23.21.150.121',
    //   'stun:stun01.sipphone.com',
    //   'stun:stun.ekiga.net',
    //   'stun:stun.fwdnet.net',
    //   'stun:stun.ideasip.com',
    //   'stun:stun.iptel.org',
    //   'stun:stun.rixtelecom.se',
    //   'stun:stun.schlund.de',
    //   'stun:stunserver.org',
    //   'stun:stun.softjoys.com',
    //   'stun:stun.voiparound.com',
    //   'stun:stun.voipbuster.com',
    //   'stun:stun.voipstunt.com',
    //   'stun:stun.voxgratia.org',
    //   'stun:stun.xten.com'
    // ];
    // this.pc = new RTCPeerConnection({
    //   iceServers: freeStunServers.map((server) => ({ urls: server }))
    // });
    this.pc = new RTCPeerConnection();
    this.stream = new MediaStream();

    this.pc.ontrack = (event) => {
      // 将视频 | 音频轨道，加入流对象，流对象赋值给 video.srcObject 直接播放
      this.stream?.addTrack(event.track);
      // console.log(this.stream)
    }
  }
  /**
   * 开始播放
   */
  async play(url: string) {
    const conf = this.init(url);
    // 配置，只“接收”视频与音频流
    this.pc?.addTransceiver('audio', { direction: 'recvonly' });
    this.pc?.addTransceiver('video', { direction: 'recvonly' });

    // 创建 offer
    const offer = await this.pc?.createOffer();
    // 设置 offer 描述
    await this.pc?.setLocalDescription(offer);

    const data = {
      api: conf.apiUrl,
      tid: conf.tid,
      streamurl: conf.streamUrl,
      clientip: null,
      sdp: offer?.sdp
    };
    console.log('Generated offer: ', data);

    const session = await (await fetch(conf.apiUrl, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(data)
    })).json();
    console.log('Got Answer: ', session);
    // 根据返回的信令设置对端描述
    await this.pc?.setRemoteDescription(new RTCSessionDescription({
      type: 'answer',
      sdp: session.sdp
    }));

    session.simulator = conf.schema + '//' + conf.urlObject.server + ':' + conf.port + '/rtc/v1/nack/';
    return session;
  }
  close() {
    //  终止接收流，对象回收
    if (this.pc) {
      this.pc.close();
      this.pc.onicecandidate = null;
      this.pc.ontrack = null;
      this.pc = null;
    }
  }

  init(webrtcUrl: string) {
    const urlObject = this.urlParse(webrtcUrl);
    // If user specifies the schema, use it as API schema.
    let schema = urlObject.user_query.schema;
    schema = schema ? schema + ':' : window.location.protocol;

    let port = urlObject.port || '1985';
    if (schema === 'https:') {
      port = urlObject.port || '443';
    }

    // @see https://github.com/rtcdn/rtcdn-draft
    let api = urlObject.user_query.play || this.defaultPath;
    if (api.lastIndexOf('/') !== api.length - 1) {
      api += '/';
    }

    let apiUrl = schema + '//' + urlObject.server + ':' + port + api;
    for (var key in urlObject.user_query) {
      if (key !== 'api' && key !== 'play') {
        apiUrl += '&' + key + '=' + urlObject.user_query[key];
      }
    }
    // Replace /rtc/v1/play/&k=v to /rtc/v1/play/?k=v
    apiUrl = apiUrl.replace(api + '&', api + '?');

    const streamUrl = urlObject.url;

    return {
      apiUrl,
      streamUrl,
      schema,
      urlObject,
      port,
      tid: Number(Math.floor(new Date().getTime() * Math.random() * 100)).toString(16).substr(0, 7)
    };
  }

  urlParse(url: string) {
    const a = document.createElement('a');
    a.href = url.replace('rtmp://', 'http://')
      .replace('webrtc://', 'http://')
      .replace('rtc://', 'http://');
    let vhost = a.hostname;
    let app = a.pathname.substr(1, a.pathname.lastIndexOf('/') - 1);
    const stream = a.pathname.substr(a.pathname.lastIndexOf('/') + 1);
    // parse the vhost in the params of app, that srs supports.
    app = app.replace('...vhost...', '?vhost=');
    if (app.indexOf('?') >= 0) {
      const params = app.substr(app.indexOf('?'));
      app = app.substr(0, app.indexOf('?'));

      if (params.indexOf('vhost=') > 0) {
        vhost = params.substr(params.indexOf('vhost=') + 'vhost='.length);
        if (vhost.indexOf('&') > 0) {
          vhost = vhost.substr(0, vhost.indexOf('&'));
        }
      }
    }
    // when vhost equals to server, and server is ip,
    // the vhost is __defaultVhost__
    if (a.hostname === vhost) {
      const re = /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/;
      if (re.test(a.hostname)) {
        vhost = '__defaultVhost__';
      }
    }

    // parse the schema
    let schema = 'rtmp';
    if (url.indexOf('://') > 0) {
      schema = url.substr(0, url.indexOf('://'));
    }

    let port = a.port;
    if (!port) {
      if (schema === 'http') {
        port = '80';
      } else if (schema === 'https') {
        port = '443';
      } else if (schema === 'rtmp') {
        port = '1935';
      }
    }

    const ret: any = {
      url,
      schema,
      server: a.hostname,
      port,
      vhost,
      app,
      stream
    };
    this.fillQuery(a.search, ret);

    // For webrtc API, we use 443 if page is https, or schema specified it.
    if (!ret.port) {
      if (schema === 'webrtc' || schema === 'rtc') {
        if (ret.user_query.schema === 'https') {
          ret.port = '443';
        } else if (window.location.href.indexOf('https://') === 0) {
          ret.port = '443';
        } else {
          // For WebRTC, SRS use 1985 as default API port.
          ret.port = '1985';
        }
      }
    }

    return ret;
  }
  fillQuery(query_string: string, obj: any) {
    obj.user_query = {};
    if (query_string.length === 0) {
      return;
    }

    // split again for angularjs.
    if (query_string.indexOf('?') >= 0) {
      query_string = query_string.split('?')[1];
    }

    const queries = query_string.split('&');

    for (const query of queries) {
      const [key, value] = query.split('=');
      obj[key] = value;
      obj.user_query[key] = value;
    }

    // alias domain for vhost.
    if (obj.domain) {
      obj.vhost = obj.domain;
    }
  }
}
